package com.aries.dubbo.like.rpc.client.util;

import com.aries.dubbo.like.rpc.client.MatchUtil;
import com.aries.dubbo.like.rpc.common.ResponseWrapper;
import com.aries.dubbo.like.rpc.common.client.ServerRequest;
import com.aries.dubbo.like.rpc.common.codec.ByteBufConst;
import com.aries.dubbo.like.rpc.common.codec.SeriazeHelper;
import com.aries.dubbo.like.rpc.common.util.IDGenerator;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;

/**
 * Created with IntelliJ IDEA.
 * Author: aries
 * Date: 2018/8/25
 * Description: 异步请求类
 */
public class AsyncRemoteInvoke {
    /**
     * 发送请求后会当即返回ResponseWrapper对象，调用者需要判断ResponseWrapper是否ok。ok后getData无阻塞，否则将会阻塞。
     *
     * @param clz         接口的class
     * @param methodName  请求方法名
     * @param requestData 请求的参数
     * @return
     */
    public static ResponseWrapper requestAsync(Class<?> clz, String methodName, Object... requestData) {
        ServerRequest serverRequest = new ServerRequest();
        serverRequest.setClz(clz.getName());
        serverRequest.setId(IDGenerator.getId());
        Class<?>[] paramTypes = new Class<?>[requestData.length];
        for (int i = 0; i < requestData.length; i++) {
            paramTypes[i] = requestData[i].getClass();
        }
        serverRequest.setParamTypes(paramTypes);
        serverRequest.setParams(requestData);
        serverRequest.setMethodName(methodName);
        Channel channel = ServiceDiscoveryUtil.getServiceChannel(clz);
        ByteBuf byteBuf = Unpooled.directBuffer();
        byteBuf.writeBytes(SeriazeHelper.encodeServerRequest(serverRequest));
        byteBuf.writeBytes(ByteBufConst.Delimiter());
        if (channel == null) {
            throw new RuntimeException("interface:" + clz.getName() +
                    " has no service provide!");
        }
        if (!channel.isWritable()) {
            throw new RuntimeException("interface:" + clz.getName() +
                    " remote provider may be dead!");
        }
        MatchUtil.add(serverRequest.getId());
        channel.writeAndFlush(byteBuf);
        return MatchUtil.get(serverRequest.getId());
    }
}
